/*--- braces.c ---------------------------- Listing 2-8 ---------
 * Checks that braces, brackets, and parentheses are properly
 * paired in a C program. If they're not, an error message
 * is printed to stderr saying at what line the unmatched
 * opening item is found. Uses a stack.
 *
 * Usage: braces filename.ext
 *-------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stacks.h"

int main ( int argc, char *argv[] )
{
    FILE *fin;                  /* file we'll be reading from */
    char buffer[128];           /* read file into this buffer */

    int line_count;             /* current line count */
    struct StkElement *stk_el;  /* scratch stack element */
    Stack *stk;                 /* the stack we will use */
    char ch;                    /* character we're examining */
    int i;                      /* for loop count */

    if ( argc != 2 )
    {
        fprintf ( stderr, "Usage: braces filename.ext\n" );
        exit ( EXIT_FAILURE );
    }

    fin = fopen ( argv[1], "rt" );
    if ( fin == NULL )
    {
        fprintf ( stderr, "Cannot open/find %s\n", argv[1] );
        exit ( EXIT_FAILURE );
    }

    /* Create and initialize the stack */

    stk = CreateStack ( 40 );   /* create a stack of 40 items */
    if ( stk == NULL )
    {
        fprintf ( stderr, "Insufficient Memory\n" );
        exit ( EXIT_FAILURE );
    }

    /* Create the scratch stack element */

    stk_el = (struct StkElement *)
                malloc ( sizeof ( struct StkElement ));
    if ( stk_el == NULL )
    {
        fprintf ( stderr, "Insufficient memory\n" );
        exit ( EXIT_FAILURE );
    }

    line_count = 0;

    while ( ! feof ( fin ))
    {
        /* read a line of a C program */
        if ( fgets ( buffer, 127, fin ) == NULL )
            break;

        line_count += 1;

        /* get rid of the trailing carriage return */
        buffer [ strlen ( buffer ) - 1 ] = '\0';

        /* scan and process braces, brackets, and parentheses */
        for ( i = 0; buffer[i] != '\0'; i++ )
        {
            switch ( ch = buffer[i] )
            {
            case '(':
            case '[':
            case '{':
                stk_el->opener  = ch;
                stk_el->line_no = line_count;
                if ( ! PushElement ( stk, stk_el ))
                {
                    fprintf ( stderr, "Out of stack space\n" );
                    exit ( EXIT_FAILURE );
                }
                break;
            case ')':
            case ']':
            case '}':
                if ( ! PopElement ( stk, stk_el ))
                    fprintf ( stderr, "Stray %c at line %d\n",
                                ch,  line_count );
                else
                if (( ch == ')'&& stk_el->opener != '(' ) ||
                    ( ch == ']'&& stk_el->opener != '[' ) ||
                    ( ch == '}'&& stk_el->opener != '{' ))
                    fprintf ( stderr,
                      "%c at line %d not matched by %c at line %d\n",
                       ch, line_count,
                       stk_el->opener, stk_el->line_no );
                break;
            default:
                continue;
            }
        }
    }

    /*  We are at the end of file. Are there unmatched items? */

    if ( ViewElement ( stk, 0 ) != NULL )
        while ( PopElement ( stk, stk_el ) != 0 )
            fprintf ( stderr, "%c from line %d unmatched\n",
                        stk_el->opener, stk_el->line_no );

    fprintf ( stderr, "Error checking complete\n" );

    fclose ( fin );
    return ( EXIT_SUCCESS );
}
